package com.excel.util.manager;

import java.io.File;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.sql.Date;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;


import com.excel.util.antichem.ReportBuilder;
import com.excel.util.entity.BodyField;
import com.excel.util.entity.GenericField;
import com.excel.util.entity.ImageField;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;

public class ReportManager 
{
	private Document			document	= null;//org.dom4j.Document
	private ReportBuilder		builder; 
	private Element				bodyElement	= null;

	private List<GenericField>	heads		= null;
	private Map<String,List<BodyField>>		bodys		= null;
	private List<GenericField>	foots		= null;
	private List<ImageField>	image		= null;
	private String bodyKey 					= null;
	
	public ReportBuilder getBuilder()
	{
		return builder;
	}

	public void setBuilder(ReportBuilder builder)
	{
		this.builder = builder;
	}
	//==============================================================================//
	/**
	 * @描述：这个方法用于加载Xml配置文件，取得节点中的所有信息。
	 * @author Yangcl
	 */
	private void loadXmlMapping(String mappingURL)
	{
		File xmlConfigFile = new File(mappingURL);
		SAXReader saxReader = new SAXReader();
		try
		{
			document = saxReader.read(xmlConfigFile);//org.dom4j.Document
		}
		catch (DocumentException e)
		{ 
			e.printStackTrace();
		}

		Element rootElement = document.getRootElement();// 获取根节点：ReportMapping
		heads = head(rootElement);
		bodys = body(rootElement);
		foots = foot(rootElement);
		image = image(rootElement);
		
	}
	//==============================================================================//
	/**
	 * 分别遍历xml文件的head\body\foot\image 
	 */
	private List<GenericField> head(Element rootElement)
	{
		List<GenericField> headerList = new ArrayList<GenericField>(); 
		Element headerElement = rootElement.element("Header"); 
		if(headerElement != null){
			for (Iterator iter = headerElement.elementIterator(); iter.hasNext();)
			{
				Element element = (Element) iter.next(); 
				// 取得Field节点下 <name>的值
				String xml_Name = element.elementTextTrim("name"); 
				String xml_Row = element.elementTextTrim("beginRow");
				String xml_Cell = element.elementTextTrim("beginCell");
	
				int intFieldRow = new Integer(xml_Row);
				int intFieldCell = new Integer(xml_Cell);
	
				// 放入实体类中
				GenericField gf = new GenericField();
				gf.setName(xml_Name); 
				gf.setBeginRow(intFieldRow);
				gf.setBeginCell(intFieldCell); 
				headerList.add(gf);
			}
		}
		return headerList;
	}
	
	private Map<String,List<BodyField>> body(Element rootElement)
	{
		//存放Body节点。以其属性name为Key，节点List为Value
		Map<String,List<BodyField>> bodyMaps = new HashMap<String,List<BodyField>>();
		
		@SuppressWarnings("unchecked")
		List<Element> bodyEleList = rootElement.elements("Body");//<Body>节点list集合
		for(Iterator ite = bodyEleList.iterator();ite.hasNext();)//遍历其中的一个<Body>节点
		{	//<Body name="Tap1" startRow="10" finishRow="22" sheetIndex="2">
			Element element = (Element) ite.next();
			
			String bodyName = element.attribute("name").getValue();
			String startRow = element.attribute("startRow").getValue();
			String finishRow = element.attribute("finishRow").getValue();
			String sheetIndex = element.attribute("sheetIndex").getValue();
			String Key = bodyName + "/" + startRow + "/" + finishRow + "/" + sheetIndex;
			bodyKey = Key;
//			setBodyKey(Key);
			List<BodyField> bodylist = new LinkedList<BodyField>(); // 存储Body所有节点  
			for (Iterator iter = element.elementIterator(); iter.hasNext();)
			{
				Element ele = (Element) iter.next();
				String xml_Name = ele.elementTextTrim("name"); 
				String xml_Cell = ele.elementTextTrim("beginCell"); 
				
				int intFieldCell = new Integer(xml_Cell); 
				BodyField bf = new BodyField();			
				bf.setName(xml_Name); 
				bf.setBeginCell(intFieldCell);
				bodylist.add(bf); 
			}
			bodyMaps.put(Key, bodylist);
			
		} 
		return bodyMaps;
	}
	private List<BodyField> body1(Element rootElement)
	{
		List<BodyField> bodylist = new LinkedList<BodyField>();// 存储Body所有节点
		
		bodyElement = rootElement.element("Body"); 
		for (Iterator iter = bodyElement.elementIterator(); iter.hasNext();)
		{ 
			Element element = (Element) iter.next(); 
			String xml_Name = element.elementTextTrim("name"); 
			String xml_Cell = element.elementTextTrim("beginCell");//这个变量会用到
			
			int intFieldCell = new Integer(xml_Cell);
			
			BodyField bf = new BodyField();			
			bf.setName(xml_Name); 
			bf.setBeginCell(intFieldCell);
			bodylist.add(bf);
		} 
		return bodylist;
	}
	private List<GenericField> foot(Element rootElement)
	{
		List<GenericField> footlist = new LinkedList<GenericField>(); 
		Element footElement = rootElement.element("Footer");
		if(footElement != null){
			for (Iterator iter = footElement.elementIterator(); iter.hasNext();)
			{
				Element element = (Element) iter.next(); 
				String xml_Name = element.elementTextTrim("name"); 
				String xml_Row = element.elementTextTrim("beginRow");
				String xml_Cell = element.elementTextTrim("beginCell");
	
				// 转换为 int类型数据 
				int intFieldRow = new Integer(xml_Row);
				int intFieldCell = new Integer(xml_Cell);
	
				// 放入实体类中
				GenericField gf = new GenericField();
				gf.setName(xml_Name); 
				gf.setBeginRow(intFieldRow);
				gf.setBeginCell(intFieldCell);
	
				footlist.add(gf);
			}
		}
		return footlist;
	}
	private List<ImageField> image(Element rootElement)
	{
		List<ImageField> imagelist = new LinkedList<ImageField>();
		Element imageElement = rootElement.element("Images");
        if(imageElement != null){
			for (Iterator iter = imageElement.elementIterator(); iter.hasNext();)
			{
				Element element = (Element) iter.next();
				String xml_Name = element.elementTextTrim("name");
				//表示图片是以文本形式还是文件流形式写入
				String xml_ImageInputStream = element.elementTextTrim("imageInputStream");
				String xml_Dx1 = element.elementTextTrim("Dx1");
				String xml_Dy1 = element.elementTextTrim("Dy1");
				String xml_Dx2 = element.elementTextTrim("Dx2");
				String xml_Dy2 = element.elementTextTrim("Dy2");
				String xml_shortCol1 = element.elementTextTrim("shortCol1");
				String xml_row1 = element.elementTextTrim("row1");
				String xml_shortCol2 = element.elementTextTrim("shortCol2");
				String xml_row2 = element.elementTextTrim("row2");
	
				// 转换数据类型
				int intFieldDx1 = new Integer(xml_Dx1);
				int intFieldDy1 = new Integer(xml_Dy1);
				int intFieldDx2 = new Integer(xml_Dx2);
				int intFieldDy2 = new Integer(xml_Dy2);
				short intFieldCol1 = new Short(xml_shortCol1);
				int intFieldRow1 = new Integer(xml_row1);
				short intFieldCol2 = new Short(xml_shortCol2);
				int intFieldRow2 = new Integer(xml_row2);
	
				// 放入实体类中
				ImageField image = new ImageField();
				image.setName(xml_Name);
				image.setImageInputStream(xml_ImageInputStream);
				image.setDx1(intFieldDx1);
				image.setDy1(intFieldDy1);
				image.setDx2(intFieldDx2);
				image.setDy2(intFieldDy2);
				image.setShortCol1(intFieldCol1);
				image.setRow1(intFieldRow1);
				image.setShortCol2(intFieldCol2);
				image.setRow2(intFieldRow2);
	
				imagelist.add(image);
			}
        }
		return imagelist;

	}
	//==============================================================================//

	private void processData(String jsonString)
	{
		DecimalFormat format = new DecimalFormat("#");
		GsonBuilder gbuilder = new GsonBuilder().setDateFormat("yyyy-MM-dd").registerTypeAdapter(Object.class, new NaturalDeserializer());
		Gson gson = gbuilder.create();
		Object natural = gson.fromJson(jsonString, Object.class);

		Map gsonMap = (Map) natural;
		// 解析并遍历Map
		Iterator mapIter = gsonMap.entrySet().iterator();

		while (mapIter.hasNext())
		{
			Entry me = (Entry) mapIter.next();
			String name = (String) me.getKey(); // 取出外部map传入的 Key 值
			Object value = (Object) me.getValue();// 取出外部map传入的 value 值
//			System.out.println("Json Name = "+name);
			for (int i = 0; i < heads.size(); i++)
			{

				if (heads.get(i).getName().equals(name))
				{
					
					String values = "";
					if(value.getClass().getName().equals("java.lang.Double")){
						values =  format.format(value)+" ";
					}else{
						values = (String) value;
					}
					int beginRow = heads.get(i).getBeginRow();
					int beginCell = heads.get(i).getBeginCell();
					if(!"".equals(values) && values != null){
						getBuilder().writeInTemplate(values, beginRow, beginCell);
					}
					break;
				}
			}
			
			Iterator ite = bodys.entrySet().iterator();
			while(ite.hasNext())
			{
				Entry en = (Entry) ite.next();
				String Key = (String) en.getKey();//取出Body的属性名称 
				String [] s =Key.split("/");
				
				String bodyName = s[0];
				String aa = s[1];
				String bb = s[2];
				String cc = s[3];
				int startRow = new Integer(aa); // 强制转化为 int
				int finishRow = new Integer(bb);
				int sheetIndex = new Integer(cc);
				
				List<BodyField> bodyListValue = (List<BodyField>) en.getValue();
				int num = 1;
				if(bodyName.equals(name))
				{
					List<Map<String,String>> listValue = (List<Map<String,String>>) value;
                    int idRow=1;
					for (int a = 0; a < listValue.size(); a++)
					{
						Map<String, String> bodyMap = (Map<String, String>) listValue.get(a);
						Iterator bodyIter = bodyMap.entrySet().iterator();
						
						while (bodyIter.hasNext())
						{
							Entry meBody = (Entry) bodyIter.next();
							String nameBody = String.valueOf(meBody.getKey());
							String valueBody = "";
							Double valueBody1 = 0.0;
							if(meBody.getValue().getClass().getName().equals("java.lang.Double")){
								valueBody1 =  (Double)meBody.getValue();
								for (BodyField bodyField : bodyListValue)
								{
									if (bodyField.getName().equals(nameBody))
									{
										int beginCell = bodyField.getBeginCell();
//										if("id".equals(nameBody)){
//											getBuilder().writeInTemplate(sheetIndex, Integer.toString(idRow), startRow - 1, beginCell);
//										}else{
											getBuilder().writeInTemplateDouble(sheetIndex, valueBody1, startRow - 1, beginCell);
//										}
										
									}
								} 
							}else{
								valueBody = String.valueOf(meBody.getValue());
								for (BodyField bodyField : bodyListValue)
								{
									if (bodyField.getName().equals(nameBody))
									{
										int beginCell = bodyField.getBeginCell();
//										if("id".equals(nameBody)){
//											getBuilder().writeInTemplate(sheetIndex, Integer.toString(idRow), startRow - 1, beginCell);
//										}else{
											getBuilder().writeInTemplate(sheetIndex, valueBody, startRow - 1, beginCell);
//										}
										
									}
								} 
							}
//							String valueBody = String.valueOf(meBody.getValue());
							
						}
//						if (startRow < finishRow)
//						{
							idRow++;
							startRow++;
//						}
					}
				}
				
			}
			for (int j = 0; j < foots.size(); j++)
			{
				if (foots.get(j).getName().equals(name))
				{
					String values = (String) value;
					int beginRow = foots.get(j).getBeginRow();
					int beginCell = foots.get(j).getBeginCell();
//					System.out.println("values:"+values+"\n");
//					System.out.println("beginRow:"+beginRow+"  beginCell:" + beginCell+"\n");
					
					getBuilder().writeInTemplate(values, beginRow, beginCell);
					break;
				}
	
			}
	
			for (int k = 0; k < image.size(); k++)
			{
				if (image.get(k).getName().equals(name))
				{
					String values = (String) value;
					int dx1 = image.get(k).getDx1();
					int dy1 = image.get(k).getDy1();
					int dx2 = image.get(k).getDx2();
					int dy2 = image.get(k).getDy2();
					short col1 = image.get(k).getShortCol1();
					int row1 = image.get(k).getRow1();
					short col2 = image.get(k).getShortCol2();
					int row2 = image.get(k).getRow2();
	
					getBuilder().writeInTemplate(values, dx1, dy1, dx2, dy2,col1, row1, col2, row2);
					break;
				}
			}
		}

	}
	/**
	 * @return
	 * 读取head
	 */
	private Map readData()
	{
		GsonBuilder gbuilder = new GsonBuilder().setDateFormat("yyyy-MM-dd").registerTypeAdapter(Object.class, new NaturalDeserializer());
		Map map = new HashMap();
		// 解析并遍历Map
		for (int i = 0; i < heads.size(); i++)
		{
			String name = heads.get(i).getName();
			int beginRow = heads.get(i).getBeginRow();
			int beginCell = heads.get(i).getBeginCell();
			map.put(name, getBuilder().readTemplate(beginRow, beginCell));
		}
		
		return map;
	}
	/**
	 * @return
	 * 读取body
	 * rowNum:excel行数
	 */
	private List readBodyData(Integer rowNum,String bodyKey){
		GsonBuilder gbuilder = new GsonBuilder().setDateFormat("yyyy-MM-dd").registerTypeAdapter(Object.class, new NaturalDeserializer());
//		System.out.println(bodyKey+"====================");
//		System.out.println((String)getBodyKey()+"========ds======================");
//		Iterator ite = bodys.entrySet().iterator();
		List<BodyField> body =  bodys.get(bodyKey);
//		while(ite.hasNext())
//		{
//			Entry en = (Entry) ite.next();
//			body = (List<BodyField>) en.getValue();
//		}
		List list = new ArrayList();
		for(int i=3;i<=rowNum;i++){
			Map map = new HashMap();
			// 解析并遍历Map
			for (int j = 0; j < body.size(); j++){
				String name = body.get(j).getName();
				int beginRow = i;
				int beginCell = body.get(j).getBeginCell();
				if(!"".equals(getBuilder().readTemplate(beginRow, beginCell)) && getBuilder().readTemplate(beginRow, beginCell)!=null){
					map.put(name,getBuilder().readTemplate(beginRow, beginCell));
				}
			}
			list.add(map);
		}
		return list;
	}

	private static class NaturalDeserializer implements	JsonDeserializer<Object>
		{
			// 请参考：http://stackoverflow.com/questions/2779251/convert-json-to-hashmap-using-gson-in-java
			public Object deserialize(JsonElement json, Type typeOfT,
					JsonDeserializationContext context)
			{
				if (json.isJsonNull())
					return null;
				else if (json.isJsonPrimitive())
					return handlePrimitive(json.getAsJsonPrimitive());
				else if (json.isJsonArray())
					return handleArray(json.getAsJsonArray(), context);
				else
					return handleObject(json.getAsJsonObject(), context);
			}

			private Object handlePrimitive(JsonPrimitive json)
			{
				if (json.isBoolean())
					return json.getAsBoolean();
				else if (json.isString())
					return json.getAsString();
				else
				{
					BigDecimal bigDec = json.getAsBigDecimal();
					// Find out if it is an int type
					try
					{
						bigDec.toBigIntegerExact();
						try
						{
							return bigDec.intValueExact();
						}
						catch (ArithmeticException e)
						{

						}

						return bigDec.longValue();
					}
					catch (ArithmeticException e)
					{

					}
					// Just return it as a double
					return bigDec.doubleValue();
				}
			}

			private Object handleArray(JsonArray json,JsonDeserializationContext context)
			{
				Object[] array = new Object[json.size()];

				for (int i = 0; i < array.length; i++)
				{
					array[i] = context.deserialize(json.get(i), Object.class);
				}

				return array;
			}

			private Object handleObject(JsonObject json,JsonDeserializationContext context)
			{
				Map<String, Object> map = new HashMap<String, Object>();
				for (Entry<String, JsonElement> entry : json.entrySet())
				{
					map.put(entry.getKey(),
							context.deserialize(entry.getValue(), Object.class));
				}

				return map;
			}

		}
	
	public void doReport(String excelURL,String xmlURL,String jsonString,String saveURL)
	{
		ReportBuilder rb = new ReportBuilder(); 
		rb.loadTemplate(excelURL); 
		this.setBuilder(rb);
		this.loadXmlMapping(xmlURL); 
		this.processData(jsonString);
		rb.SaveTemplate(saveURL);
	}
	/**
	 * @param excelURL
	 * @param xmlURL
	 * @param jsonString
	 * @param saveURL
	 * 导出列表后还有合并单元格的表尾的表格
	 * cellNum需要合并的列数
	 */
	public void doReportFoot(String excelURL,String xmlURL,String jsonString,String saveURL,Integer rowNum,String[] str,String[] hejiStr,Integer cellNum)
	{
		ReportBuilder rb = new ReportBuilder(); 
		rb.loadTemplateFoot(excelURL,rowNum,str,hejiStr,cellNum); 
		this.setBuilder(rb);
		this.loadXmlMapping(xmlURL); 
		this.processData(jsonString);
		rb.SaveTemplate(saveURL);
	}
	public  Map doRead(String excelURL,String xmlURL)
	{
		ReportBuilder rb = new ReportBuilder(); 
		rb.loadTemplate(excelURL); 
		this.setBuilder(rb);
		this.loadXmlMapping(xmlURL); 
		Map map =  this.readData();
		return map;
	}
	public  List doReadBody(String excelURL,String xmlURL) throws Exception{
		ReportBuilder rb = new ReportBuilder(); 
		rb.loadTemplate(excelURL); 
		this.setBuilder(rb);
		this.loadXmlMapping(xmlURL); 
		List list =  this.readBodyData(rb.getRowNum(),bodyKey);
		return list;
	}
	
	
}
